import java.util.Vector;

import processing.core.PApplet;
import processing.core.PVector;

public class MC_SoftBody extends PApplet {

	private static final long serialVersionUID = 1L;
	/**
	 * Soft Body 
	 * by Ira Greenberg.  
	 * 
	 * Softbody dynamics simulation using curveVertex() and curveTightness().
	 */

	Vector<PVector> pointsBeingDrawn;
	Vector<PVector> pointsToDraw;
	
	// center point
	float centerX = 0; 
	float centerY = 0;
	
	float radius = 45;
	float rotAngle = -90;
	float accelX = 0; 
	float accelY = 0;
	float springing = 0.0009f; 
	float damping = 0.98f;

	//corner nodes
	int nodes = 4;
	Vector<PVector> nodeStart = new Vector<PVector>();
	Vector<PVector> node = new Vector<PVector>();
	Vector<Float> angles = new Vector<Float>();
	Vector<Float> frequencies = new Vector<Float>();

	// soft-body dynamics
	float organicConstant = 1;

	boolean firstTime = true;

	public void setup() {
		size(640, 360);
		//center shape in window
		centerX = width/2;
		centerY = height/2;
		// iniitalize frequencies for corner nodes
		for (int i=0; i<nodes; i++) {
			frequencies.add(random(5,12));
			//frequency[i] = random(5, 12);
		}
		noStroke();
		//smooth();
		frameRate(30);
		pointsBeingDrawn = new Vector<PVector>();
		pointsToDraw = new Vector<PVector>();
	}

	public void draw() {
		System.out.println(node.size());
		background(0);
		drawShape();
		moveShape();
		for (PVector point : pointsToDraw) {
			stroke(255);
			point(point.x, point.y);
		}
		//node.clear();
		//nodeStart.clear();
	}

	public void drawShape() {
		if(firstTime) {
//			for(int i = 0; i < nodes; i++){
//				num1[i] = random(100);
//				num2[i] = random(100);
//			}

			firstTime = false;
		} else {
			for (int i = 0; i < nodes; i++) {
				float curX = centerX + cos(radians(rotAngle)) * radius;
				float curY = centerY + sin(radians(rotAngle)) * radius;
				//nodeStartX[i] = curX;
				//nodeStartY[i] = curY;
				nodeStart.add(new PVector(curX, curY));
				rotAngle = rotAngle + 360.0f/nodes;
			}
			// draw polygon
			curveTightness(0.4f);
			fill(255);
			beginShape();
			for (int i = 0; i < node.size(); i++) {
				//curveVertex(nodeX[i], nodeY[i]);
				curveVertex(node.elementAt(i).x, node.elementAt(i).y);
			}
			for (int i = 0; i < node.size() - 1; i++) {
				//curveVertex(nodeX[i], nodeY[i]);
				curveVertex(node.elementAt(i).x, node.elementAt(i).y);
			}
			node.clear();
			endShape(CLOSE);
		}
	}

	public void moveShape() {
		//move center point
		float deltaX = mouseX-centerX;
		float deltaY = mouseY-centerY;

		// create springing effect
		deltaX = deltaX * springing;
		deltaY = deltaY * springing;
		accelX = accelX + deltaX;
		accelY = accelY + deltaY;

		// move predator's center
		centerX = centerX + accelX;
		centerY = centerY + accelY;

		// slow down springing
		accelX = accelX * damping;
		accelY = accelY * damping;

		// change curve tightness
		organicConstant = 1 - ((abs(accelX)+abs(accelY))*.1f);

		for (int i = 0; i < frequencies.size(); i++) {
			if(angles.size() != frequencies.size()){
				angles.add(frequencies.elementAt(i));
			} else {
				angles.add(angles.elementAt(i) + frequencies.elementAt(i));
			}
		}
		
		//move nodes
		for (int i = 0; i < nodeStart.size(); i++) {
			float addX = sin(radians(angles.elementAt(i))) * (accelX*2);
			float addY = sin(radians(angles.elementAt(i))) * (accelY*2);
			float curX = nodeStart.elementAt(i).x + addX;
			float curY = nodeStart.elementAt(i).y + addY;
			node.add(new PVector(curX, curY));
			//nodeStart.clear();
			//nodeX[i] = nodeStartX[i] + sin(radians(angle[i])) * (accelX*2);
			//nodeY[i] = nodeStartY[i] + sin(radians(angle[i])) * (accelY*2);
			
			//angle[i] = angle[i] + frequency[i];
		}
		nodeStart.clear();
	}
	
	public boolean contem(PVector current){
		boolean contem = false;
		for (PVector point : pointsBeingDrawn) {
			float cX = current.x;
			float cY = current.y;
			float pX = point.x;
			float pY = point.y;
			if(cX == pX && cY == pY){
				contem = true;
			}
		}
		return contem;
	}

	@Override
	public void mouseDragged() {
		PVector current = new PVector(mouseX, mouseY);
		if(!contem(current)){
			pointsBeingDrawn.add(current);
		} else {
			System.out.println("Ok");
			pointsToDraw = pointsBeingDrawn;
			nodeStart = pointsToDraw;
			pointsBeingDrawn.clear();
		}
	}

	static public void main(String args[]) {
		PApplet.main(new String[] { "--bgcolor=#FFFFFF", "MC_SoftBody" });
	}
}
